package systems.database;

import ihm.views.options.ATKjOptionPane;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.DriverManager;
import java.util.Properties;

import systems.configurations.SystemConfiguration;
import systems.exceptions.database.NotConnectedException;
import systems.exceptions.database.StatementIsNullException;
import systems.languages.MultiLanguages;

/**
 * Provides a Connection and Statement handler for DataBase using a JDBC class.
 * This class is based on the singleton design pattern.
 * @author Baptiste Legrand and Benjamin Orman
 * @version 1.0
 */
public class DataBaseHandler {
  private static DataBaseHandler  dbHandler = new DataBaseHandler();
  private static Connection       connection;
  private static Statement        statement;
  private static Properties       props;

  /**
   * This constructor create a DataBaseHandler object.
   * It loads the properties store in the SystemConfig.xml file.
   * These properties are using to instantiate the connection and statement 
   * objects.
   * After reading these properties, the JDBC class will try to establish a 
   * connection
   * to the remote database.
   * @version 1.0
   */
  private DataBaseHandler()
  {
    String driver  = SystemConfiguration.getProperties().getProperty("db.driver");
    String charSet = SystemConfiguration.getProperties().getProperty("db.charSet");
    String usr     = SystemConfiguration.getProperties().getProperty("db.remote.user");
    String pass    = SystemConfiguration.getProperties().getProperty("db.remote.pass");
    String url     = SystemConfiguration.getProperties().getProperty("db.url");


    DataBaseHandler.props = new Properties();
    DataBaseHandler.props.put("user",      usr);
    DataBaseHandler.props.put("password",  pass);
    DataBaseHandler.props.put("charSet",   charSet);

    try {
      Class.forName(driver);
      DataBaseHandler.connection = DriverManager.getConnection(url, usr, pass);

      DataBaseHandler.statement  = DataBaseHandler.connection.createStatement();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    } catch (SQLException e) {
      String errorMessage = MultiLanguages.getProperties("exception.DataBase.notConnected") + "\n"+
      MultiLanguages.getProperties("exception.DataBase.manualChange");
      ATKjOptionPane.showMessageDialog(null, errorMessage);
    }
  }

  
  /**
   * Provides a method to execute a query and catch Exception.
   * It will try to execute the query (@see Statement.executeQuery) and return 
   * the resultSet.
   * If the <i>Statement.executeQuery</i> method throw an <i>SQLException</i> 
   * then this method will look for the cause.
   * So, it throws 
   *  - an <i>NotConnectedException</i> if the connection does not seems to be
   *  established;
   *  - an <i>StatementIsNullException</i> if the statement does not seems to 
   * be instantiate;
   * If none of these exceptions are throws then, the method print the stack 
   * trace on the standard output.
   * @param query - the query to be send to the database
   * @return either the row count for <code>INSERT</code>, <code>UPDATE</code> 
   * or <code>DELETE</code> statements, or <code>0</code> for SQL statements
   * that return nothing
   * @throws NotConnectedException - if the program does not seems to be 
   * connected to the database.
   * @throws StatementIsNullException - if the connection statement is set to 
   * null.
   * @version 1.0
   */
  public static ResultSet query(String query)
  throws NotConnectedException, StatementIsNullException
  {
    //System.out.println("[Query : ]"+query);
    try {
      return DataBaseHandler.statement.executeQuery(query);
    } catch (SQLException e) {
      if(DataBaseHandler.connection == null)
        throw new NotConnectedException();
      if(DataBaseHandler.statement == null)
        throw new StatementIsNullException();
      System.out.println("[DataBaseHandler -> query ]: "+
          "Error while the programm tried to execute the query '"+
          query+"'. Here is the stack :");
      e.printStackTrace();
    }
    return null;
  }

  /**
   * This method return the DataBaseHandler instance.
   * @return DataBaseHandler : the DataBaseHandler instance.
   * @version 1.0
   */
  public static DataBaseHandler getInstance()
  {
    return DataBaseHandler.dbHandler;
  }

  /**
   * This method return the statement of the DataBaseHandler instance.
   * @return Statement : the statement.
   * @version 1.0
   */
  public static Statement getStatement()
  {
    return DataBaseHandler.statement;
  }
}
